package com.zhijian.warehouse.manage.service.impl;

import com.gg.reader.api.dal.GClient;
import com.gg.reader.api.protocol.gx.EnumG;
import com.gg.reader.api.protocol.gx.MsgBaseInventoryEpc;
import com.zhijian.util.BeanUtil;
import com.zhijian.util.MapBuilderUtil;
import com.zhijian.util.NetUtil;
import com.zhijian.warehouse.manage.config.Constants;
import com.zhijian.warehouse.manage.config.access.AccessConfig;
import com.zhijian.warehouse.manage.entity.vo.request.SseMessageSearchVo;
import com.zhijian.warehouse.manage.entity.vo.response.AccessAioAndroidBingVo;
import com.zhijian.warehouse.manage.enums.SseClientEnum;
import com.zhijian.warehouse.manage.service.AccessNotifyService;
import com.zhijian.warehouse.manage.service.AccessOptService;
import com.zhijian.warehouse.manage.service.CacheDao;
import com.zhijian.warehouse.manage.service.sse.ConnectedHandler;
import com.zhijian.warehouse.manage.service.sse.SseClient;
import com.zhijian.warehouse.manage.service.sse.SseMessage;
import com.zhijian.warehouse.manage.util.AssertCommonUtil;
import com.zhijian.warehouse.manage.util.ServletUtils;
import com.zhijian.warehouse.manage.util.access.AccessAioUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author DANTA
 */
@Slf4j
@Service
public class AccessNotifyServiceImpl implements AccessNotifyService {
    private static final Map<String, GClient> AIO_CLIENT_MAP = new HashMap<>();
    private final String clientId = String.format("%s_%s", SseClientEnum.RAED_RFID.type, Constants.Redis.RFID_AIO);
    private final String RECONNECT = String.format("%s_%s", SseClientEnum.RECONNECT.type, Constants.Redis.RFID_RECONNECT);
    @Autowired
    private SseClient client;
    @Autowired
    private CacheDao cacheDao;
    @Autowired
    private AccessConfig accessConfig;
    @Autowired
    private AccessOptService accessOptService;
    
    
    @Override
    public String getReadEpc(SseMessageSearchVo sseMessageSearchVo, HttpServletRequest request) {
        //取出对应一体机客户端
        GClient gClient = AIO_CLIENT_MAP.get(NetUtil.getIPV4(request));
        if (BeanUtil.isEmpty(gClient)) {
            log.error("一体机读写器客户端未连接, androidIp:{}", NetUtil.getIPV4(request));
            return null;
        }
        // 发送读取标签指令
        MsgBaseInventoryEpc msgBaseInventoryEpc = new MsgBaseInventoryEpc();
        //1号天线， 1、2号天线 = EnumG.AntennaNo_1|EnumG.AntennaNo_2
        msgBaseInventoryEpc.setAntennaEnable(EnumG.AntennaNo_1);
        msgBaseInventoryEpc.setInventoryMode(EnumG.InventoryMode_Single);
        
        AIO_CLIENT_MAP.get(NetUtil.getIPV4(request)).sendSynMsg(msgBaseInventoryEpc);
        if (0x00 == msgBaseInventoryEpc.getRtCode()) {
            log.info("MsgBaseInventoryEpc[OK].");
        }
        else {
            log.error("MsgBaseInventoryEpc[ERROR]. rtCode:{}, rtMsg:{}", msgBaseInventoryEpc.getRtCode(), msgBaseInventoryEpc.getRtMsg());
            AssertCommonUtil.check(true, "感应器未连接或连接中断");
        }
        String ipClientId = String.format("%s_ip_%s", clientId, NetUtil.getIPV4(ServletUtils.getRequest()));
        String epc = null;
        int attempt = 0;
        //50毫秒等待一次 配合前端500毫秒的轮询,将单次读取标签成功率提高
        while (epc == null && attempt < 6) {
            epc = cacheDao.support().get(ipClientId);
            if (epc != null) {
                cacheDao.support().del(ipClientId);
                break;
            }
            attempt++;
            try {
                // 暂停50毫秒
                Thread.sleep(50);
            } catch (InterruptedException e) {
                log.error("Thread interrupted", e);
                Thread.currentThread().interrupt(); // 恢复中断状态
            }
        }
        return epc;
    }
    
    /**
     * {@inheritDoc}
     */
    @Override
    public void initReadEpc(SseMessageSearchVo sseMessageSearchVo, GClient client, AccessAioAndroidBingVo accessAioAndroidBingVo) {
        String ipv4 = accessAioAndroidBingVo.getAndroidIpAddr();
        if (client != null) {
            AIO_CLIENT_MAP.put(ipv4, client);
            AccessAioUtil.initAioAccess(client, accessConfig, accessOptService, accessAioAndroidBingVo);
        }
    }
    
    /**
     * {@inheritDoc}
     */
    @Override
    public SseEmitter sendConnect(Long doorId) {
        return client.send(String.format("%s_%s", RECONNECT, doorId));
    }
    
    /**
     * {@inheritDoc}
     */
    @Override
    public void rfIdConnect(String epc, String androidIp) {
        String ipClientId = String.format("%s_ip_%s", clientId, androidIp);
        //将数据放入缓存 2秒过期
        //1分钟内重复过门不做处理
        cacheDao.support().set(ipClientId, epc, 1, TimeUnit.SECONDS);
    }
    
    /**
     * {@inheritDoc}
     */
    @Override
    public SseEmitter doorReconnect(boolean flag, String msg, Long doorId) {
        String clientIdFmt = String.format("%s_%s", RECONNECT, doorId);
        return client.connect(clientIdFmt, new ConnectedHandler() {
            @Override
            public SseMessage handle(String clientId) {
                return SseMessage.builder().type(SseClientEnum.RAED_RFID.type).data(MapBuilderUtil.builder()
                        .put("status", flag)
                        .put("msg", msg)
                        .build()).build();
            }
        });
    }
}
